package org.lsy.filter;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.net.InetSocketAddress;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author liusy95
 * @version 1.0
 * @date 2020/7/30
 */
@Component
@Slf4j
public class AntiSwipeFilter implements GlobalFilter, Ordered {

    @Value("${filter.threshold}")
    private int threshold;

    @Value("${filter.duration}")
    private int duration;

    private static final String PREFIX = "filter::";

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        String ip = request.getRemoteAddress().getHostString();
        if (!redisTemplate.hasKey(PREFIX + ip)) {
            redisTemplate.opsForValue().set(PREFIX + ip, "0", duration, TimeUnit.MINUTES);
        }
        String countStr = redisTemplate.opsForValue().get(PREFIX + ip);
        if (Integer.parseInt(countStr) > threshold) {
            response.getHeaders().add("Content-Type", "text/plain;charset=UTF-8");
            // 状态码
            response.setStatusCode(HttpStatus.SEE_OTHER);
            String data = "您频繁进⾏注册，请求已被拒绝";
            DataBuffer wrap = response.bufferFactory().wrap(data.getBytes());
            return response.writeWith(Mono.just(wrap));
        } else {
            redisTemplate.opsForValue().increment(PREFIX + ip);
        }
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 0;
    }
}
